import os.path
import time

from mylibs.lib import *
from universal.root_path import *
from universal.widget_common import lineEdit_act,Table_widget,lineEdit_act_file,\
    Table_widget_setItem,SaveDirPATH,SetCellWidget
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt, QRect, qDebug, QSize
from PyQt5.QtGui import QImageReader, QPainter, QPixmap, QImage
try:
    from vtkmodules.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
    import vtkmodules.all as vtk
except Exception as e:
    print(e)
import threading
__appname__ = '章鱼博士'

class MainWidget_3d(QWidget):
    def __init__(self):
        super(MainWidget_3d,self).__init__()
        self.layout = QHBoxLayout(self)
        self.Init_vtk()
        #--------------界面&布局-------------
        self.Left_Tab()
        self.right_Init()
        # self.layout.addWidget(self.leftwidget)
        self.layout.addWidget(self.widgetRight)

        #-------------配置参数-------------
        self.Init_parameter()
        self.setMouseTracking(True)

    def Left_Tab(self):
        self.leftwidget = QTabWidget()
        para_tableWidget = self.Left_Init()
        self.leftwidget.addTab(para_tableWidget, "基础参数")

    def Left_Init(self):
        para_tableWidget = Table_widget(self, 2, 2)
        name_list = ["读取路径","当前图像"]
        Table_widget_setItem(para_tableWidget, name_list)
        self.readPath = lineEdit_act(self)
        self.showName = QLineEdit()
        self.showName.setReadOnly(True)
        self.readPath.textChanged.connect(self.LineEvent)
        para_tableWidget_list = [self.readPath,self.showName]
        SetCellWidget(para_tableWidget, para_tableWidget_list)
        return para_tableWidget


    def right_Init(self):
        self.widgetRight = QFrame()
        
        self.widgetDisplay = QWidget()
        # self.LabelLayout = QHBoxLayout(self.widgetDisplay)
        self.vtk_show = QVTKRenderWindowInteractor()
        self.vtk_show.setMinimumWidth(400)
        # self.vtk_show.resize(self.widgetDisplay.size())
        self.vtk_show.SetInteractorStyle(vtk.vtkInteractorStyleMultiTouchCamera())
        self.vtk_show.GetRenderWindow().AddRenderer(self.renderer)
        self.vtk_show.Render()
        self.vtk_show.Start()

        self.i_ren = self.vtk_show.GetRenderWindow().GetInteractor()
        self.i_ren.Initialize()

        self.imageLabel = MyLabel()
        # self.imageLabel.setMinimumWidth(600)
        self.imageLabel.setStyleSheet('''QLabel{background-color:rgb(50, 80, 100);}''')

        self.ButtonNextPre()
        self.layoutRight = QVBoxLayout(self.widgetRight)
        self.slider = QSlider(self, minimum=0, maximum=100, orientation=Qt.Horizontal)
        self.slider.setMinimum(0)
        self.slider.setMaximum(100)
        self.slider.setSingleStep(5)
        self.slider.setValue(50)
        self.slider.valueChanged.connect(self.updateImage)
        self.layoutRight.addWidget(self.slider)
        self.layoutRight.addWidget(self.widgetDisplay)

    def ButtonNextPre(self):
        buttonLeft = QPushButton('上一张')
        buttonLeft.clicked.connect(self.PreImg)
        buttonLeft.setMaximumSize(45, 45)
        buttonRight = QPushButton('下一张')
        buttonRight.clicked.connect(self.NextImg)
        buttonRight.setMaximumSize(45, 45)
        buttonLeft.setStyleSheet('''QPushButton{background:#8BA583;
                border-radius:5px;}QPushButton:hover{background:#CDA593;}''')
        buttonRight.setStyleSheet('''QPushButton{background:#8BA583;
                border-radius:5px;}QPushButton:hover{background:#CDA593;}''')

        # buttonLeft.setIcon(QIcon("icons/Left.png"))  # 将图片路径通过setIcon的方式写入按钮中
        # buttonLeft.setIconSize(QSize(96, 96))  # 设置图片在按钮中的大小

        self.buttonLayout = QHBoxLayout()
        self.buttonLayout.addWidget(buttonLeft, Qt.AlignLeft)
        self.buttonLayout.addWidget(self.imageLabel)
        self.buttonLayout.addWidget(self.vtk_show)
        # self.buttonLayout.addSpacing(1000)
        self.buttonLayout.addWidget(buttonRight, Qt.AlignRight)
        self.widgetDisplay.setLayout(self.buttonLayout)


    def NextImg(self):
        if self.index + 1 == len(self.imgList):
            return
        if self.index == len(self.imgList):
            return
        self.index = self.index + 1
        self.currentImg = self.imgList[self.index]
        self.read_tif(self.currentImg)
        self.showName.setText(os.path.basename(self.currentImg))

    def PreImg(self):
        if self.index == 0:
            return
        if self.index == len(self.imgList):
            return
        self.index = self.index - 1
        self.currentImg = self.imgList[self.index]
        self.read_tif(self.currentImg)
        self.showName.setText(os.path.basename(self.currentImg))

    def Init_parameter(self):
        self.imgList = []
        self.index = 0
        self.dstImage = np.array([])
        self.grayImage = np.array([])
        self.rgbImage = np.array([])

    def Init_vtk(self):
        self.pointCloud = VtkPointCloud()
        self.renderer = vtk.vtkRenderer()
        self.renderer.AddActor(self.pointCloud.vtkActor)
        self.renderer.SetBackground(.2, .3, .4)
        self.renderer.ResetCamera()

        # Render Window


    def updateImage(self):
        if self.rgbImage.any() and self.grayImage.any():
            self.dstImage = cv2.addWeighted(self.rgbImage, float(self.slider.value() / 100), self.grayImage, float(100 - self.slider.value()) / 100, 0.2)
            self.imageLabel.SetPic(self.cvToQImage(self.dstImage))
            QApplication.processEvents()


    def LineEvent(self):
        path = self.readPath.text()
        if not os.path.exists(path):
            return
        self.imgList = self.scanAllImages(path)
        if len(self.imgList)>0:
            self.index = 0
            self.read_tif(self.imgList[0])
            self.showName.setText(os.path.basename(self.imgList[0]))

    def read_tif(self,filename):
        time1 = time.time()
        if filename != "":
            try:
                self.grayImage = cv2.imdecode(np.fromfile(filename, dtype=np.uint8), cv2.IMREAD_COLOR)
                depthFilename = filename.replace("GA", "HA")
                depthFilename = depthFilename.replace(".jpg", ".tif")
                depthImg = cv2.imdecode(np.fromfile(depthFilename, dtype=np.int16), -1)
                depthImg.dtype = 'int16'
                depthImg_u = np.unique(depthImg)
                print(depthImg_u[1],depthImg_u[-1])

                self.rgbImage = self.depthToColor(depthImg, depthImg_u[1], depthImg_u[-1])
                self.pointCloud.clearPoints()
                self.pointCloud.setRange(-depthImg_u[-1] / 1000 + 0.05, -depthImg_u[1] / 1000 - 0.05)
                for h in range(0, depthImg.shape[0], 4):
                    for w in range(0, depthImg.shape[1], 4):
                        if depthImg[h, w] > -10000:
                            point = (w * 0.01, h * 0.01, float(-depthImg[h, w] / 1000.0))
                            self.pointCloud.addPoint(point)

                self.dstImage = cv2.addWeighted(self.rgbImage, float(self.slider.value() / 100), self.grayImage,
                                               float(100 - self.slider.value()) / 100, 0.2)

                self.imageLabel.SetPic(self.cvToQImage(self.dstImage))

                self.renderer.ResetCamera()
                QApplication.processEvents()
                self.vtk_show.update()
                print("Time:",time.time()-time1)
            except:
                pass
    #Tools
    def scanAllImages(self, folderPath):
        extensions = ['.%s' % fmt.data().decode("ascii").lower() for fmt in QImageReader.supportedImageFormats()]
        extensions.remove('.tif')
        images = []
        for root, dirs, files in os.walk(folderPath):
            for file in files:
                if file.lower().endswith(tuple(extensions)):
                    relativePath = os.path.join(root, file)
                    path = str(os.path.abspath(relativePath))
                    images.append(path)
        images.sort(key=lambda x: x.lower())
        return images

    def cvToQImage(self, data):
        # 8-bits unsigned, NO. OF CHANNELS=1
        if data.dtype == np.uint8:
            channels = 1 if len(data.shape) == 2 else data.shape[2]
        if channels == 3:  # CV_8UC3
            # Copy input Mat
            # Create QImage with same dimensions as input Mat
            img = QImage(data, data.shape[1], data.shape[0], data.strides[0], QImage.Format_RGB888)
            return img.rgbSwapped()
        elif channels == 1:
            # Copy input Mat
            # Create QImage with same dimensions as input Mat
            data = cv2.cvtColor(data, cv2.COLOR_BGR2GRAY)
            img = QImage(data, data.shape[1], data.shape[0], data.shape[1], QImage.Format_Indexed8)
            # print(data)
            return img
        else:
            qDebug("ERROR: numpy.ndarray could not be converted to QImage. Channels = %d" % data.shape[2])
            return QImage()


    def depthToColor(self, depthImg, min, max):
        x = depthImg

        # newArray = np.where(x < -30000, min, x)
        # minIndex = np.argwhere(x < -30000)

        img_dep = (depthImg - min) / (max - min) * 255
        img_dep = img_dep.astype(np.uint8)
        result = cv2.applyColorMap(img_dep, cv2.COLORMAP_JET)
        result[np.where(x < -30000)] = 0

        return result


class MyLabel(QLabel):
    def __init__(self, parent=None):
        super(MyLabel, self).__init__(parent)
        self.srcImage = None
        self.bTempPixmap = None
        self.ZoomValue = 1.0
        self.XPtInterval = 0
        self.YPtInterval = 0
        self.setMinimumWidth(650)
        self.Pressed = False
        self.bZoom = True
        self.OldPos = None
        self.nMovePos = None
        self.intPenWidth = 1

    def SetPic(self, image):
        self.srcImage = image
        self.update()

    def setZoom(self, bZoom):
        self.bZoom = bZoom

    def paintEvent(self, event):
        painter = QPainter(self)
        tmpPixMap = QPixmap(self.width(), self.height())
        tmpPixMap.fill(Qt.transparent)
        painter.begin(tmpPixMap)

        if self.srcImage != None:
            width = min(self.srcImage.width(), self.width())
            height = width * 1.0 / (self.srcImage.width() * 1.0 / self.srcImage.height())
            height = min(height, self.height())
            width = height * 1.0 * (self.srcImage.width() * 1.0 / self.srcImage.height())

            painter.translate(self.width() / 2 + self.XPtInterval, self.height() / 2 + self.YPtInterval)
            # painter.translate(width, height)
            painter.scale(self.ZoomValue, self.ZoomValue)

            picRect = QRect(int(-width / 2), int(-height / 2), int(width), int(height))

            painter.drawImage(picRect, self.srcImage)
        painter.end()

    def wheelEvent(self, event):
        if self.bZoom == False:
            return
        value = event.angleDelta().y()

        if value > 0:
            self.OnZoomInImage()
        else:
            self.OnZoomOutImage()

        self.update()

    def mouseDoubleClickEvent(self, event):
        self.OnPresetImage()

    def mousePressEvent(self, event):
        self.OldPos = event.pos()
        self.Pressed = True

    def mouseMoveEvent(self, event):
        self.setCursor(Qt.SizeAllCursor)
        pos = event.pos()
        xPtInterval = pos.x() - self.OldPos.x()
        yPtInterval = pos.y() - self.OldPos.y()

        self.XPtInterval += xPtInterval
        self.YPtInterval += yPtInterval

        self.OldPos = pos
        self.update()

    def mouseReleaseEvent(self, event):
        self.Pressed = False
        self.setCursor(Qt.ArrowCursor)

    def OnZoomInImage(self):
        self.ZoomValue += 0.05
        self.update()

    def OnZoomOutImage(self):
        self.ZoomValue -= 0.05
        if self.ZoomValue <= 0:
            self.ZoomValue = 0.05
            return

        self.update()

    def OnPresetImage(self):
        self.ZoomValue = 1.0
        self.XPtInterval = 0
        self.YPtInterval = 0
        self.update()


class VtkPointCloud:

    def __init__(self):
        self.vtkPolyData = vtk.vtkPolyData()
        self.clearPoints()
        # mapper = vtk.vtkPolyDataMapper()
        # mapper.SetInputData(self.vtkPolyData)
        # mapper.SetColorModeToDefault()
        # mapper.SetScalarRange(zMin, zMax)
        # mapper.SetScalarVisibility(1)
        self.vtkActor = vtk.vtkActor()
        # self.vtkActor.GetProperty().SetPointSize(4)
        # self.vtkActor.SetMapper(mapper)

    def setRange(self, zMin=-0.2, zMax=1):
        mapper = vtk.vtkPolyDataMapper()
        mapper.SetInputData(self.vtkPolyData)
        mapper.SetColorModeToDefault()
        mapper.SetScalarRange(zMin, zMax)
        mapper.SetScalarVisibility(1)
        self.vtkActor.GetProperty().SetPointSize(4)
        self.vtkActor.SetMapper(mapper)

    def addPoint(self, point):
        pointId = self.vtkPoints.InsertNextPoint(point[:])
        self.vtkDepth.InsertNextValue(point[2])
        self.vtkCells.InsertNextCell(1)
        self.vtkCells.InsertCellPoint(pointId)

        self.vtkCells.Modified()
        self.vtkPoints.Modified()
        self.vtkDepth.Modified()

    def clearPoints(self):
        self.vtkPoints = vtk.vtkPoints()
        self.vtkCells = vtk.vtkCellArray()
        self.vtkDepth = vtk.vtkDoubleArray()
        self.vtkDepth.SetName('DepthArray')
        self.vtkPolyData.SetPoints(self.vtkPoints)
        self.vtkPolyData.SetVerts(self.vtkCells)
        self.vtkPolyData.GetPointData().SetScalars(self.vtkDepth)
        self.vtkPolyData.GetPointData().SetActiveScalars('DepthArray')

#
#
# if __name__ == '__main__':
#     app = QApplication(sys.argv)
#     main_window = MainWidget_3d()
#     main_window.show()
#     sys.exit(app.exec())